'''
Description: 
Author: Zilu
Date: 2021-11-04 12:52:47
Version: 
LastEditTime: 2021-11-04 13:26:18
LastEditors: Zilu
'''

# 定义默认参数的时候，必须指向不变对象，否则可能在使用过程中，改变了默认参数
def add_end(L=[]):
    L.append("END")
    return L


add_end([1, 2, 3])
add_end(['a', 'b', 'c'])

# 下面使用默认参数就发生了变化
add_end()
add_end()

# 可以使用 None 不变对象来避免
def add_end_fix(L=None):
    if L == None:
        L = []
    L.append('END')
    return L


add_end_fix()
add_end_fix()

# 使用 * 作为可变参数，接收 0 个或多个数据
def cal(*numbers):      # numbers是一个tuple
    sum = 0
    for num in numbers:
        sum += num
    return sum


sum = cal(1, 2, 3, 4, 5)

# 也可以使用*将list或tuple 的元素作为可变参数传递
nums = (3, 4, 5, 6, 7)
sum1 = cal(*nums)

# 用**可以使用关键字参数，关键字参数在函数内部自动组装成dict
def person(name, age, **kw):
    print('name:', name, 'age:', age, 'others:', kw)


person('Bob', 25)
person("Mike", 36)
person('Adam', 12, city="BeiJing", gender="M", job='Engineering')

# 和可变参数类似，也可以用**解析dict作为参数参数
extra = {'city': 'BeiJing', 'Job': 'Engeering'}
person('Alice', 35, **extra)        # kw获得的是extra的一份copy，改变kw不影响extra

# 命名关键字参数，*是一个分隔符，后面的参数被视为命名关键字参数
def person_def(name, age, *, city, job):
    print(name, age, city, job)


person_def("Alice", 31, city='BeiJing', job="teacher")
# 下面多了个参数，使用错误
# person_def("Alice",31,city='BeiJing',job="teacher",salary=56789)

# 如果有可变参数，则不用额外的*分隔符
def person_alt(name, age, *args, city, job):
    print(name, age, args, city, job)

person_alt("Alice", 31, 1, 2, 3, 4, 5, 6, city='BeiJing', job="teacher")

# 命名关键字参数可以使用缺省值

# 必选参数、默认参数、可变参数、关键字参数和命名关键字参数，这5种参数都可以组合使用
# 参数顺序必须是：必选参数、默认参数、可变参数、命名关键字参数和关键字参数
def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)

# 也可以使用tuple和dict直接调用上述函数
args = (1, 2, 3, 4)
kw = {'d':99, 'x':'#'}
f1(*args,**kw)
args = (1, 2, 3)
kw = {'d': 88, 'x': '#'}
f2(*args,**kw)

# 因此，对于任意函数，都可以用 f(*args,**kw)的形式调用，无论其参数如何定义
